//
// See the file COPYING for redistribution information.
//

#ifndef __NAIPAX_PPQ_HPP__
#define __NAIPAX_PPQ_HPP__

#include <stdint.h>
#include <string>
#include <vector>
#include <db_cxx.h>

namespace Naipax {
    template<typename DataType>
    class PpqDefaultSeralizer {
    public:
        // The prototypes are not determined yet since it is not used
        // by now. Only the specialized template for std::string is
        // used.
        void Serialize() {}
        void Unserialize() {}
    };

    template<> 
    class PpqDefaultSeralizer <std::string> {};

    /** Persistent Priority Queue
     *
     * Two things to be noted:
     * 
     * Currently, only Ppq<std::string> is workable. Usage with other
     * data types has no effect.
     *
     * There is currently no locking is done in the
     * implementation. Locking on the queue of a specific priority
     * level will be added in the future.
     */
    template <typename DataType, 
              typename Serializer = PpqDefaultSeralizer<DataType> >
    class Ppq {
    public:
        Ppq(const char *pPathname, uint32_t PriorityLevels = 2);

        ~Ppq();

        int32_t Enqueue(const DataType &rData, uint32_t Level);

        int32_t Dequeue(std::vector<DataType> &rData, uint32_t MaxItems);

        uint32_t PriorityLevels() const { return _mPriorityLevels; }
        
    private:
        Db **_mpDbs;
        uint32_t _mPriorityLevels;
    };

    template <>
    class Ppq<std::string>{
    public:
        /** Constructor
         *
         * @param pPathname Where queue files are stored.
         * @param PriorityLevels The number of priorities.
         *        One queue file is created for one priority level.
         * @exception Error::INVALID_ARGUMENT if pPathname is NULL
         *            or PriorityLevels is 0.
         * @exception Error::CANNOT_OPEN_DB if any database of priority 
         *            queue cannot be opened.
         */
        Ppq(const char *pPathname, uint32_t PriorityLevels = 2);

        /// Destructor
        ~Ppq();

        /** Put an item in queue of a specified level.
         *
         * @param rData The data to be inserted.
         * @param Level The level of priority queue.
         * @return 0 if rData is successfully inserted.
         * @exception Error::DATA_OUT_OF_RANGE if Level exceeds the maximum
         *            priority level. Data is not inserted.
         * @exception Error::INVALID_ARGUMENT if rData.length() is zero.
         */
        int32_t Enqueue(const std::string &rData, uint32_t Level);

        /** Remove an item from queue with the highest priority and
         * return it.
         *
         * @param rData The data to be inserted.
         * @param MaxItems The maximum number of data to be returned.
         * @return 0 if rData is successfully dequeued.
         * @exception Error::CANNOT_DELETE_DATA if data cannot be deleted from queue.
         * @exception Error::CANNOT_CLOSE_DB if data cannot be deleted from queue.
         */
        int32_t Dequeue(std::vector<std::string> &rData, uint32_t MaxItems);

        /// Return the number of priority levels.
        uint32_t PriorityLevels() const { return _mPriorityLevels; }
        
    private:
        Db **_mpDbs;
        uint32_t _mPriorityLevels;
    };
};

#endif // __NAIPAX_PPQ_HPP__
